﻿using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;

using WP = DocumentFormat.OpenXml.Wordprocessing;
using wp = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using a = DocumentFormat.OpenXml.Drawing;
using pic = DocumentFormat.OpenXml.Drawing.Pictures;

namespace Expect.Report.Word
{
    using System;
    using System.Drawing;

    static class ImagesHelper
    {
        public static string GraphicDataUri = "http://schemas.openxmlformats.org/drawingml/2006/picture";

        public static ImagePartType GetImageType(this Bitmap bmp)
        {
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Bmp.Guid) return ImagePartType.Bmp;
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Gif.Guid) return ImagePartType.Gif;
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Icon.Guid) return ImagePartType.Icon;
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Jpeg.Guid) return ImagePartType.Jpeg;
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Png.Guid) return ImagePartType.Png;
            if (bmp.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Tiff.Guid) return ImagePartType.Tiff;
            
            throw new InvalidOperationException("Unknown image format");
        }

        public static void AddImage(this MainDocumentPart mainpart, string filename)
        {
            byte[] imageFileBytes;
            Bitmap image = null;

            // Open a stream on the image file and read it's contents.
            using (FileStream fsImageFile = System.IO.File.OpenRead(filename))
            {
                imageFileBytes = new byte[fsImageFile.Length];
                fsImageFile.Read(imageFileBytes, 0, imageFileBytes.Length);
                var imagePart = mainpart.AddImagePart(ImagePartType.Jpeg);
                imagePart.FeedData(fsImageFile);

                fsImageFile.Position = 0;
                image = new Bitmap(fsImageFile);
                AddImage(mainpart, filename, image, imagePart);
            }
        }

        public static void AddImage(this MainDocumentPart mainpart, string name, Bitmap image)
        {
            ImagePart imagePart = mainpart.AddImagePart(image.GetImageType());
            using (MemoryStream stream = new MemoryStream())
            {
                image.Save(stream, image.RawFormat);
                stream.Position = 0;
                imagePart.FeedData(stream);
            }

            AddImage(mainpart, name, image, imagePart);
        }

        public static void AddImage(this MainDocumentPart mainpart, string name, Stream strm)
        {
            var image = new Bitmap(strm);
            ImagePart imagePart = mainpart.AddImagePart(image.GetImageType());
            strm.Position = 0;
            imagePart.FeedData(strm);
            AddImage(mainpart, name, image, imagePart);
        }

        public static void AddImage(this MainDocumentPart mainpart, string name, Bitmap image, ImagePart imagePart)
        {            
            long imageWidthEMU = (long)((image.Width / image.HorizontalResolution) * 914400L);
            long imageHeightEMU = (long)((image.Height / image.VerticalResolution) * 914400L);            

            WP.Paragraph para =
            new WP.Paragraph(
              new ParagraphProperties(new Justification() { Val = JustificationValues.Center }),
              new WP.Run(
                new WP.Drawing(
                  new wp.Inline(

                    new wp.Extent()
                    {
                        Cx = imageWidthEMU,
                        Cy = imageHeightEMU
                    },

                    new wp.EffectExtent()
                    {
                        LeftEdge = 19050L,
                        TopEdge = 0L,
                        RightEdge = 9525L,
                        BottomEdge = 0L
                    },

                    new wp.DocProperties()
                    {
                        Id = (UInt32Value)1U,
                        Name = "Inline Text Wrapping Picture",
                        Description = GraphicDataUri
                    },

                    new wp.NonVisualGraphicFrameDrawingProperties(
                      new a.GraphicFrameLocks() { NoChangeAspect = true }),

                    new a.Graphic(
                      new a.GraphicData(
                        new pic.Picture(

                          new pic.NonVisualPictureProperties(
                            new pic.NonVisualDrawingProperties()
                            {
                                Id = (UInt32Value)0U,
                                Name = name
                            },
                            new pic.NonVisualPictureDrawingProperties()),

                          new pic.BlipFill(
                            new a.Blip() { Embed = mainpart.GetIdOfPart(imagePart) },
                            new a.Stretch(
                              new a.FillRectangle())),

                          new pic.ShapeProperties(
                            new a.Transform2D(
                              new a.Offset() { X = 0L, Y = 0L },
                              new a.Extents()
                              {
                                  Cx = imageWidthEMU,
                                  Cy = imageHeightEMU
                              }),

                            new a.PresetGeometry(
                              new a.AdjustValueList()
                            ) { Preset = a.ShapeTypeValues.Rectangle }))
                      ) { Uri = GraphicDataUri })
                  )
                  {
                      DistanceFromTop = (UInt32Value)0U,
                      DistanceFromBottom = (UInt32Value)0U,
                      DistanceFromLeft = (UInt32Value)0U,
                      DistanceFromRight = (UInt32Value)0U
                  }))

            );

            mainpart.Document.Body.Append(para);
        }

    }
}
